﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
using System.Xml.Linq;


using AMPLibrary;
using AMPLibrary.Collections;

namespace AMPLibrary.Media
{
    [Serializable]
    public class AutomaticPlaylist : ISerializable
    {
        private int DEFAULT_LIMIT = 100;

        public string PlaylistName
        {
            get;
            set;
        }

        public List<String> Genres
        {
            get;
            set;
        }

        public List<string> Years
        {
            get;
            set;
        }

        public int ItemLimit
        {
            get;
            set;
        }

        public MediaPlaybackFrequencyState MediaPlaybackFrequencyState
        {
            get;
            set;
        }

        public MediaFavoriteState MediaFavoriteState
        {
            get;
            set;
        }

        public Collection<MediaFile> Media
        {
            get;
            private set;
        }

        public UserMediaRating UserMediaRating
        {
            get;
            set;
        }

        public RecentlyAddedMedia RecentlyAddedMedia
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public AutomaticPlaylist()
        {
            Init();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="playlistName"></param>
        public AutomaticPlaylist(string playlistName)
        {
            Init();

            PlaylistName = playlistName;
        }

        /// <summary>
        /// 
        /// </summary>
        private void Init()
        {
            PlaylistName = string.Empty;
            Genres = new List<string>();
            Years = new List<string>();
            ItemLimit = 0;
            UserMediaRating = AMPLibrary.Media.UserMediaRating.NoConsideration;
            MediaPlaybackFrequencyState = MediaPlaybackFrequencyState.NoConsideration;
            MediaFavoriteState = AMPLibrary.Media.MediaFavoriteState.UseAllMedia;
            RecentlyAddedMedia = AMPLibrary.Media.RecentlyAddedMedia.NoConsideration;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Collection<MediaFile> GenerateList(int listSize)
        {
            if (listSize > 100)
                ItemLimit = 100;

            if (listSize <= 0)
                ItemLimit = 1;

            this.ItemLimit = listSize;

            MusicCollection musicCollection = MusicCollection.GetMusicCollection();
            Collection<MediaFile> temporaryMediaCollection = new Collection<MediaFile>();
                        
            // if no genres were found take everything
            if (Genres.Count == 0)
                temporaryMediaCollection.AddItems(musicCollection);
            else
            {
                // search for genres
                foreach (string genre in Genres)
                {
                    foreach (MediaFile m in (from g in musicCollection where g.Tag.Genre == genre select g))
                        temporaryMediaCollection.AddItem(m);
                }
            }

            if (Years.Count != 0)
            {
                Collection<MediaFile> yearFilterTemp = new Collection<MediaFile>();

                // for each year get the media that matches both genre and year
                foreach (string year in Years)
                {
                    foreach (MediaFile m in (from y in temporaryMediaCollection where y.Tag.Year == year select y))
                        yearFilterTemp.AddItem(m);
                }

                temporaryMediaCollection.ClearItems();
                temporaryMediaCollection.AddItems(yearFilterTemp);
            }

            switch (UserMediaRating)
            {
                case AMPLibrary.Media.UserMediaRating.Unrated:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.UserMediaRating == AMPLibrary.Media.UserMediaRating.Unrated)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.OneStar:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.UserMediaRating == AMPLibrary.Media.UserMediaRating.OneStar)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.TwoStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.UserMediaRating == AMPLibrary.Media.UserMediaRating.TwoStars)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.ThreeStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.UserMediaRating == AMPLibrary.Media.UserMediaRating.ThreeStars)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.FourStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.UserMediaRating == AMPLibrary.Media.UserMediaRating.FourStars)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.FiveStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.UserMediaRating == AMPLibrary.Media.UserMediaRating.FiveStars)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.AtLeastOneStar:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if ((int)m.UserMediaRating >= 1)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.AtLeastTwoStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if ((int)m.UserMediaRating >= 2)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.AtLeastThreeStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if ((int)m.UserMediaRating >= 3)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.AtLeastFourStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if ((int)m.UserMediaRating >= 4)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;

                case AMPLibrary.Media.UserMediaRating.AtLeastFiveStars:
                    {
                        Collection<MediaFile> ratingTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if ((int)m.UserMediaRating >= 5)
                                ratingTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(ratingTemp);
                    }
                    break;
            }
            
            switch (MediaFavoriteState)
            {
                case AMPLibrary.Media.MediaFavoriteState.OnlyUseFavorites:
                    {
                        Collection<MediaFile> favoritesTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.IsFavorited == true)
                                favoritesTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(favoritesTemp);
                    }
                    break;

                case AMPLibrary.Media.MediaFavoriteState.UseAllMediaIgnoreFavorites:
                    {
                        Collection<MediaFile> favoritesTemp = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.IsFavorited == false)
                                favoritesTemp.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(favoritesTemp);
                    }
                    break;
            }

            switch (MediaPlaybackFrequencyState)
            {
                case AMPLibrary.Media.MediaPlaybackFrequencyState.Never:
                    {
                        Collection<MediaFile> lastPlayed = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.LastPlayed == DateTime.MinValue)
                                lastPlayed.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(lastPlayed);
                    }
                    break;

                case AMPLibrary.Media.MediaPlaybackFrequencyState.RecentLast250:
                    {
                        Collection<MediaFile> lastPlayed = new Collection<MediaFile>();

                        foreach (MediaFile m in (from mf in temporaryMediaCollection orderby mf.LastPlayed descending select mf).Take(250))
                        {
                            if (m.LastPlayed == DateTime.MinValue)
                                lastPlayed.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(lastPlayed);
                    }
                    break;

                case AMPLibrary.Media.MediaPlaybackFrequencyState.RecentLast500:
                    {
                        Collection<MediaFile> lastPlayed = new Collection<MediaFile>();

                        foreach (MediaFile m in (from mf in temporaryMediaCollection orderby mf.LastPlayed descending select mf).Take(500))
                        {
                            if (m.LastPlayed == DateTime.MinValue)
                                lastPlayed.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(lastPlayed);
                    }
                    break;

                case AMPLibrary.Media.MediaPlaybackFrequencyState.RecentLast750:
                    {
                        Collection<MediaFile> lastPlayed = new Collection<MediaFile>();

                        foreach (MediaFile m in (from mf in temporaryMediaCollection orderby mf.LastPlayed descending select mf).Take(750))
                        {
                            if (m.LastPlayed == DateTime.MinValue)
                                lastPlayed.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(lastPlayed);
                    }
                    break;
            }

            switch (RecentlyAddedMedia)
            {
                case AMPLibrary.Media.RecentlyAddedMedia.InTheLastWeek:
                    {
                        Collection<MediaFile> recentlyAdded = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.DateAdded > DateTime.Now.Subtract(new TimeSpan(7, 0, 0 ,0)))
                                recentlyAdded.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(recentlyAdded);
                    }
                    break;

                case AMPLibrary.Media.RecentlyAddedMedia.InTheLastTwoWeeks:
                    {
                        Collection<MediaFile> recentlyAdded = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.DateAdded > DateTime.Now.Subtract(new TimeSpan(14, 0, 0, 0)))
                                recentlyAdded.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(recentlyAdded);
                    }
                    break;

                case AMPLibrary.Media.RecentlyAddedMedia.InTheLastMonth:
                    {
                        Collection<MediaFile> recentlyAdded = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.DateAdded > DateTime.Now.Subtract(new TimeSpan(31, 0, 0, 0)))
                                recentlyAdded.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(recentlyAdded);
                    }
                    break;

                case AMPLibrary.Media.RecentlyAddedMedia.InTheLastThreeMonths:
                    {
                        Collection<MediaFile> recentlyAdded = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.DateAdded > DateTime.Now.Subtract(new TimeSpan(91, 0, 0, 0)))
                                recentlyAdded.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(recentlyAdded);
                    }
                    break;

                case AMPLibrary.Media.RecentlyAddedMedia.InTheLastSixMonths:
                    {
                        Collection<MediaFile> recentlyAdded = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.DateAdded > DateTime.Now.Subtract(new TimeSpan(182, 0, 0, 0)))
                                recentlyAdded.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(recentlyAdded);
                    }
                    break;

                case AMPLibrary.Media.RecentlyAddedMedia.InTheLastYear:
                    {
                        Collection<MediaFile> recentlyAdded = new Collection<MediaFile>();

                        foreach (MediaFile m in temporaryMediaCollection)
                        {
                            if (m.DateAdded > DateTime.Now.Subtract(new TimeSpan(365, 0, 0, 0)))
                                recentlyAdded.AddItem(m);
                        }

                        temporaryMediaCollection.ClearItems();
                        temporaryMediaCollection.AddItems(recentlyAdded);
                    }
                    break;
            }

            temporaryMediaCollection.RandomizeItems();

            return new Collection<MediaFile>(temporaryMediaCollection.Take(this.ItemLimit));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("MediaPlaybackFrequencyState", this.MediaPlaybackFrequencyState);
            info.AddValue("Genres", this.Genres);
            info.AddValue("ItemLimit", this.ItemLimit);
            info.AddValue("MediaFavoriteState", this.MediaFavoriteState);
            info.AddValue("PlaylistName", this.PlaylistName);
            info.AddValue("UserMediaRating", this.UserMediaRating);
            info.AddValue("Years", this.Years);
            info.AddValue("RecentlyAddedMedia", this.RecentlyAddedMedia);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public AutomaticPlaylist(SerializationInfo info, StreamingContext ctxt)
        {
            Init();

            this.MediaPlaybackFrequencyState = (MediaPlaybackFrequencyState)info.GetValue("MediaPlaybackFrequencyState", typeof(MediaPlaybackFrequencyState));
            this.Genres = (List<string>)info.GetValue("Genres", typeof(List<string>));
            this.ItemLimit = (int)info.GetValue("ItemLimit", typeof(int));
            this.MediaFavoriteState = (MediaFavoriteState)info.GetValue("MediaFavoriteState", typeof(MediaFavoriteState));
            this.PlaylistName = (string)info.GetValue("PlaylistName", typeof(string));
            this.UserMediaRating = (UserMediaRating)info.GetValue("UserMediaRating", typeof(UserMediaRating));
            this.Years = (List<string>)info.GetValue("Years", typeof(List<string>));
            this.RecentlyAddedMedia = (RecentlyAddedMedia)info.GetValue("RecentlyAddedMedia", typeof(RecentlyAddedMedia));
        }
    }
}
